﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Windows.UI;

namespace LinkLine
{
    public class Chess
    {
        public ChessCanvasCell Cell;
        public Color Color;
        public int X
        {
            get
            {
                if (Cell != null)
                    return Cell.X;
                else
                    return -1;
            }
        }
        public int Y
        {
            get
            {
                if (Cell != null)
                    return Cell.Y;
                else
                    return -1;
            }
        }
    }

    public class ChessCanvasCell
    {
        public int X;
        public int Y;
        public Chess Chess;
        public int Distance;
        public ChessCanvasCell Path;
    }

    public class ChessCanvas
    {
        ChessCanvasCell[,] canvas;

        public bool IsCellEmpty(int x, int y)
        {
            if (x < xTotal && y < yTotal)
                return canvas[x, y].Chess == null;
            else
                return false;
        }

        public ChessCanvas()
            : this(9, 9)
        {
        }

        public ChessCanvas(int xTotal, int yTotal)
        {
            this.xTotal = xTotal;
            this.yTotal = yTotal;
            canvas = new ChessCanvasCell[xTotal, yTotal];
            for (int i = 0; i < xTotal; i++)
            {
                for (int j = 0; j < yTotal; j++)
                {
                    canvas[i, j] = new ChessCanvasCell();
                    canvas[i, j].X = i;
                    canvas[i, j].Y = j;
                }
            }
        }

        private int xTotal;
        private int yTotal;
        private int score;
        public int XTotal { get { return xTotal; } }
        public int YTotal { get { return yTotal; } }
        public int Total { get { return xTotal * yTotal; } }
        public int Score { get { return score; } }

        public bool IsFull
        {
            get
            {
                for (int i = 0; i < xTotal; i++)
                {
                    for (int j = 0; j < yTotal; j++)
                    {
                        if (canvas[i, j].Chess == null)
                            return false;
                    }
                }
                return true;
            }
        }

        public void Clear()
        {
            for (int i = 0; i < xTotal; i++)
            {
                for (int j = 0; j < yTotal; j++)
                {
                    canvas[i, j].Chess = null;
                }
            }
            score = 0;
        }

        public bool Set(int x, int y, Chess chess)
        {
            bool reduced = false;
            if (chess != null && x < xTotal && y < yTotal)
            {
                chess.Cell = canvas[x, y];
                canvas[x, y].Chess = chess;
                reduced = Check(chess);
            }
            return reduced;
        }

        public bool Check(Chess chess)
        {
            bool reduced = false;
            int sameColorCount = 0;
            Collection<Chess> sameColorChesses = new Collection<Chess>();

            // x axsis
            int x = chess.X;
            int y = chess.Y;
            while (x > 0 && canvas[--x, y].Chess != null && canvas[x, y].Chess.Color == chess.Color)
            {
                sameColorChesses.Add(canvas[x, y].Chess);
            }
            x = chess.X;
            y = chess.Y;
            while (x < xTotal - 1 && canvas[++x, y].Chess != null && canvas[x, y].Chess.Color == chess.Color)
            {
                sameColorChesses.Add(canvas[x, y].Chess);
            }
            if (sameColorChesses.Count >= 4)
            {
                foreach (Chess sameColorChess in sameColorChesses)
                {
                    canvas[sameColorChess.X, sameColorChess.Y].Chess = null;
                }
                sameColorCount += sameColorChesses.Count;
            }
            sameColorChesses.Clear();

            // y axsis
            x = chess.X;
            y = chess.Y;
            while (y > 0 && canvas[x, --y].Chess != null && canvas[x, y].Chess.Color == chess.Color)
            {
                sameColorChesses.Add(canvas[x, y].Chess);
            }
            x = chess.X;
            y = chess.Y;
            while (y < yTotal - 1 && canvas[x, ++y].Chess != null && canvas[x, y].Chess.Color == chess.Color)
            {
                sameColorChesses.Add(canvas[x, y].Chess);
            }
            if (sameColorChesses.Count >= 4)
            {
                foreach (Chess sameColorChess in sameColorChesses)
                {
                    canvas[sameColorChess.X, sameColorChess.Y].Chess = null;
                }
                sameColorCount += sameColorChesses.Count;
            }
            sameColorChesses.Clear();

            // xy axsis
            x = chess.X;
            y = chess.Y;
            while (x > 0 && y > 0 && canvas[--x, --y].Chess != null && canvas[x, y].Chess.Color == chess.Color)
            {
                sameColorChesses.Add(canvas[x, y].Chess);
            }
            x = chess.X;
            y = chess.Y;
            while (x < xTotal - 1 && y < yTotal - 1 && canvas[++x, ++y].Chess != null && canvas[x, y].Chess.Color == chess.Color)
            {
                sameColorChesses.Add(canvas[x, y].Chess);
            }
            if (sameColorChesses.Count >= 4)
            {
                foreach (Chess sameColorChess in sameColorChesses)
                {
                    canvas[sameColorChess.X, sameColorChess.Y].Chess = null;
                }
                sameColorCount += sameColorChesses.Count;
            }
            sameColorChesses.Clear();

            // yx axsis
            x = chess.X;
            y = chess.Y;
            while (x > 0 && y < yTotal - 1 && canvas[--x, ++y].Chess != null && canvas[x, y].Chess.Color == chess.Color)
            {
                sameColorChesses.Add(canvas[x, y].Chess);
            }
            x = chess.X;
            y = chess.Y;
            while (x < xTotal - 1 && y > 0 && canvas[++x, --y].Chess != null && canvas[x, y].Chess.Color == chess.Color)
            {
                sameColorChesses.Add(canvas[x, y].Chess);
            }
            if (sameColorChesses.Count >= 4)
            {
                foreach (Chess sameColorChess in sameColorChesses)
                {
                    canvas[sameColorChess.X, sameColorChess.Y].Chess = null;
                }
                sameColorCount += sameColorChesses.Count;
            }
            sameColorChesses.Clear();

            if (sameColorCount > 0)
            {
                canvas[chess.X, chess.Y].Chess = null;
                if (sameColorCount == 4)
                {
                    score += 10;
                }
                else if (sameColorCount > 4)
                {
                    score += (int)(10 * Math.Pow(1.4, sameColorCount - 4));
                }
                reduced = true;
            }
            return reduced;
        }

        public ChessCanvasCell Cells(int x, int y)
        {
            return canvas[x, y];
        }

        public Collection<ChessCanvasCell> FindPath(int startX, int startY, int endX, int endY)
        {
            Collection<ChessCanvasCell> path = new Collection<ChessCanvasCell>();

            if (startX == endX && startY == endY)
            {
                path.Add(canvas[startX, startY]);
                return path;
            }

            for (int i = 0; i < XTotal; i++)
            {
                for (int j = 0; j < yTotal; j++)
                {
                    canvas[i, j].Distance = int.MaxValue;
                    canvas[i, j].Path = null;
                }
            }
            Queue<ChessCanvasCell> queue = new Queue<ChessCanvasCell>();
            ChessCanvasCell start = canvas[startX, startY];
            start.Distance = 0;
            queue.Enqueue(start);
            while (queue.Count != 0)
            {
                ChessCanvasCell current = queue.Dequeue();
                if (current.X > 0)
                {
                    ChessCanvasCell left = canvas[current.X - 1, current.Y];
                    if (left.Chess == null && left.Distance > current.Distance + 1)
                    {
                        left.Distance = current.Distance + 1;
                        left.Path = current;
                        queue.Enqueue(left);
                    }
                }
                if (current.X < xTotal - 1)
                {
                    ChessCanvasCell right = canvas[current.X + 1, current.Y];
                    if (right.Chess == null && right.Distance > current.Distance + 1)
                    {
                        right.Distance = current.Distance + 1;
                        right.Path = current;
                        queue.Enqueue(right);
                    }
                }
                if (current.Y > 0)
                {
                    ChessCanvasCell up = canvas[current.X, current.Y - 1];
                    if (up.Chess == null && up.Distance > current.Distance + 1)
                    {
                        up.Distance = current.Distance + 1;
                        up.Path = current;
                        queue.Enqueue(up);
                    }
                }
                if (current.Y < yTotal - 1)
                {
                    ChessCanvasCell down = canvas[current.X, current.Y + 1];
                    if (down.Chess == null && down.Distance > current.Distance + 1)
                    {
                        down.Distance = current.Distance + 1;
                        down.Path = current;
                        queue.Enqueue(down);
                    }
                }
            }
            ChessCanvasCell end = canvas[endX, endY];
            if (end.Distance < int.MaxValue)
            {
                path.Add(end);
                ChessCanvasCell ptr = end;
                while (ptr != start)
                {
                    path.Insert(0, ptr.Path);
                    ptr = ptr.Path;
                }
                path.Insert(0, ptr);
            }
            return path;
        }
    }
}
